# services/websocket_service.py
import asyncio
from collections import defaultdict
from typing import Dict, List, Optional

import socketio
from engineio.async_drivers.aiohttp import WebSocket
from socketio.exceptions import SocketIOError

from common.sqlalchemy_db import SqlalchemyX
from common.util import singleton
from modules.mod import Group
from service.GroupDBService import GroupDBService
from service.GroupService import GroupService
from service.MessageService import MessageService
from service.SocketService import SocketService
from service.UserService import UserService


@singleton
class WebsocketService:
    def __init__(
        self,
        sio: socketio.AsyncServer,
        socket_service: SocketService = SocketService(),
        user_service: UserService = UserService(),
        group_service: GroupService=  GroupService(),
        group_db_service: GroupDBService = GroupDBService(),
        message_service: MessageService = MessageService()
    ):
        self.socket_service = socket_service
        self.user_service = user_service
        self.group_service = group_service
        self.message_service = message_service
        self.active_connections: Dict[str, WebSocket] = {}
        self.session = SqlalchemyX.AsyncSessionLocal()

        self.group_db_service = group_db_service
        self.sio = sio

        # 用于存储房间和客户端之间的关系
        self.rooms_clients_map = defaultdict(set)

    async def get_clients_in_chatting_room(self, room_name: str):
        try:
            # 获取房间内的所有客户端 SID（socket.id）
            clients = self.rooms_clients_map[room_name]
            return {
                'clients': clients,
                'clientsNum': len(clients)
            }
        except Exception as e:
            raise SocketIOError({
                "message": "获取房间客户端失败",
                "error": str(e)
            })

    async def join_chatting_room(self, sid, room_name: str):
        """通过指定房间名加入聊天室"""
        try:
            # 加入房间
            await self.sio.enter_room(sid, room_name)
            self.rooms_clients_map[room_name].add(sid)


            group_mes = await self.group_db_service.get_group_mes({"group_name": room_name})
            room_user = await self.get_clients_in_chatting_room(room_name)

            return {
                'message': '加入聊天室成功',
                'groupId': group_mes.group_id,
                'groupName': room_name,
                'groupAvatar': group_mes.group_avatar,
                'groupType': group_mes.group_type,
                'roomUserNum': room_user.get("clientsNum")
            }
        except Exception as e:
            await self.sio.emit('error', {'message': '加入聊天室失败'}, room=sid)
            raise e

    async def update_socket_mes(self, socket_id: str, client_ip: str, user_id: str):

        user = await self.user_service.get_user_basic_mes({"user_id": user_id})
        await self.socket_service.update_socket( {"_id": user.get("user_socketId")}, {"socket_id": socket_id, "ip": client_ip})

    # todo
    async def guest_join_room(self, websocket: WebSocket):
        default_group = await self.group_service.get_group(self.session , {"group_type": 0 })
        room_name = default_group.group_name
        join_mes = await self.join_chatting_room(websocket, room_name)

        last_message = await self.message_service.get_last_message_by_group({  "message_to_id": default_group.group_id})
        message_from = await self.user_service.get_user_basic_mes({"user_id": last_message.message_from_id})
        last_message.message_from_name = message_from["user_name"]
        return {
            "error_code": 0,
            "data": {
                "joinMes": join_mes,
                "lastMessage": last_message
            }
        }

    async def user_join_rooms(self,sid ,user_id: str):
        groups = await self.group_service.get_user_group_mes(self.session, user_id)
        for group in groups:
            room_name = group["group_name"]
            asyncio.create_task(
                self.sio.emit('join_chating_room', {'roomName': room_name},
                         callback=lambda ack: print("服务器确认:", ack))
            )

    async def get_default_group(self):
        async with SqlalchemyX.AsyncSessionLocal() as session:
            return session.query(Group).filter(Group.group_type == 0 ).frist()